using System.Diagnostics;
using System.Windows.Input;
using DimensionsHelper.Common.Contracts.TableFormatter;
using DimensionsHelper.Common.Contracts.Services;
using DimensionsHelper.Common.Utils;

namespace DimensionsHelper.Client.ViewModels.CsvFormatter;

[DebuggerDisplay("{OutputFileName,nq}")]
public class CsvFileGroupViewModel : ObservableCollection<CsvInputFileViewModel>
{
    private string _outputFileName = string.Empty;

    public Func<string, bool>? Predicate { get; set; }

    public ICommand RemoveSelfCommand => new RelayCommand(OnRemoveSelf);

    public string OutputFileName
    {
        get => _outputFileName;

        set
        {
            if (_outputFileName.Equals(value, StringComparison.Ordinal) || (Predicate != null && !Predicate(value)))
            {
                return;
            }

            _outputFileName = value;
            OnPropertyChanged(new PropertyChangedEventArgs(nameof(OutputFileName)));
        }
    }


    public ICommand SelectOutputFileCommand => new AsyncRelayCommand(SelectOutputFile);


    public ICommand SelectInputCsvFilesCommand => new RelayCommand(SelectInputCsvFiles);

    public event Action<CsvFileGroupViewModel>? RemoveSelf;


    private void OnRemoveSelf()
    {
        RemoveSelf?.Invoke(this);
    }


    private void OnInputFileRemoveSelf(FileInfoViewModel input)
    {
        CsvInputFileViewModel inputCsv = (CsvInputFileViewModel)input;
        RemoveAt(inputCsv.Index);
        for (int i = inputCsv.Index; i < Count; i++)
        {
            this[i].Index--;
        }
    }


    private async Task SelectOutputFile()
    {
        if (await App.GetService<IFilePikerService>()!.SaveFileAsync(FileFilters.Excel) is not { Length: > 0 } outputFile)
        {
            return;
        }

        OutputFileName = outputFile;
    }


    private void MoveItemForward(CsvInputFileViewModel viewModel)
    {
        int index = viewModel.Index;

        if (index == 0)
        {
            return;
        }

        (this[index - 1], this[index]) = (this[index], this[index - 1]);

        viewModel.Index--;
        this[index].Index = index;
    }


    private void MoveItemBackward(CsvInputFileViewModel viewModel)
    {
        int index = viewModel.Index;

        if (index == Count - 1)
        {
            return;
        }

        (this[index], this[index + 1]) = (this[index + 1], this[index]);

        viewModel.Index++;
        this[index].Index = index;
    }


    private async void SelectInputCsvFiles()
    {
        IReadOnlyList<string> files = await App.GetService<IFilePikerService>()!.
            PickMultipleFilesAsync(FileFilters.Csv);

        foreach (string? file in files)
        {
            CsvInputFileViewModel input = new()
            {
                Index = Count,
                FileName = file
            };

            input.MoveBackward += MoveItemBackward;
            input.MoveForward += MoveItemForward;
            input.RemoveSelf += OnInputFileRemoveSelf;

            Add(input);
        }
    }


    public TableInputFileInfo[] ToCsvInputFileInfoArray()
    {
        return [.. this.Select(f => f.ToCsvInputFileInfo())];
    }
}


public class CsvFileGroupListViewModel : ObservableCollection<CsvFileGroupViewModel>
{
    public ICommand SelectFileGroupOutputFileCommand => new AsyncRelayCommand(SelectFileGroupOutputFile);

    private bool FileExists(string fileName)
    {
        return this.Any(f => f.OutputFileName.Equals(fileName, StringComparison.OrdinalIgnoreCase));
    }


    private void OnFileGroupRemoveSelf(CsvFileGroupViewModel model)
    {
        Remove(model);
    }


    private async Task SelectFileGroupOutputFile()
    {
        if (await App.GetService<IFilePikerService>()!.SaveFileAsync(FileFilters.Excel) is not { Length: > 0 } fileName ||
            FileExists(fileName))
        {
            return;
        }

        CsvFileGroupViewModel group = new()
        {
            Predicate = fileName => !FileExists(fileName),
            OutputFileName = fileName
        };

        group.RemoveSelf += OnFileGroupRemoveSelf;
        Add(group);
    }
}